/**
 * Copyright (c) 2011 ~ 2013 Deepin, Inc.
 *               2011 ~ 2013 jouyouyun
 *
 * Author:      jouyouyun <jouyouwen717@gmail.com>
 * Maintainer:  jouyouyun <jouyouwen717@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 **/

package main

import (
        "fmt"
        "io/ioutil"
        "os"
)

const (
        ETC_TIMEZONE  = "/etc/timezone"
        ETC_LOCALTIME = "/etc/localtime"
        ZONE_INFO_DIR = "/usr/share/zoneinfo/"
        ETC_PERM      = 0644
)

func getZoneCityList() []string {
        return zoneCityInfo
}

func setTimezone(tz string) bool {
        defer func() {
                if err := recover(); err != nil {
                        fmt.Println("Recover Error:", err)
                }
        }()

        /*
           if !zoneCityIsValid(tz) {
                   return false
           }
        */

        if !fileIsRegular(ETC_LOCALTIME) {
                return false
        }

        tzFile := ZONE_INFO_DIR + tz
        if !fileIsRegular(tzFile) {
                return false
        }

        /* Modify /etc/localtime */
        if fileIsSymlink(ETC_LOCALTIME) {
                err := os.Remove(ETC_LOCALTIME)
                if err != nil {
                        fmt.Printf("Remove '%s' failed: %s\n",
                                ETC_TIMEZONE, err)
                        return false
                }

                err = os.Symlink(tzFile, ETC_TIMEZONE)
                if err != nil {
                        fmt.Printf("Symlink '%s' to '%s' failed: %s\n",
                                tzFile, ETC_TIMEZONE, err)
                        return false
                }
        } else {
                if !copyFile(tzFile, ETC_LOCALTIME, ETC_PERM) {
                        return false
                }
        }

        /* Modify /etc/timezone */
        if !fileIsRegular(ETC_TIMEZONE) {
                return false
        }
        err := ioutil.WriteFile(ETC_TIMEZONE, []byte(tz),
                os.FileMode(ETC_PERM))
        if err != nil {
                fmt.Printf("WriteFile '%s' failed: %s\n", ETC_TIMEZONE, err)
                return false
        }

        return true
}

func copyFile(src, dest string, perm os.FileMode) bool {
        contents, err := ioutil.ReadFile(src)
        if err != nil {
                fmt.Printf("ReadFile '%s' failed: %s\n", src, err)
                return false
        }

        err = ioutil.WriteFile(dest, contents, os.FileMode(ETC_PERM))
        if err != nil {
                fmt.Printf("WriteFile '%s' failed: %s\n", dest, err)
                return false
        }

        return true
}

func getFileMode(file string) os.FileMode {
        f, err := os.Open(file)
        defer f.Close()
        if err != nil {
                fmt.Printf("Open '%s' failed: %s\n", file, err)
                panic(err)
        }

        info, err1 := f.Stat()
        if err1 != nil {
                fmt.Printf("Stat '%s' failed: %s\n", file, err1)
                panic(err1)
        }

        return info.Mode()
}

func fileIsRegular(file string) bool {
        ok := getFileMode(file).IsRegular()
        if !ok {
                fmt.Printf("'%s' is not regular\n", file)
                return false
        }

        return true
}

func fileIsDir(file string) bool {
        ok := getFileMode(file).IsDir()
        if !ok {
                fmt.Printf("'%s' is not dir\n", file)
                return false
        }

        return true
}

func fileIsSymlink(file string) bool {
        mode := getFileMode(file)
        if mode == os.ModeSymlink {
                fmt.Printf("'%s' is symlink\n", file)
                return true
        }

        return false
}

func zoneFileIsExist(file string) bool {
        if _, err := os.Stat(file); os.IsNotExist(err) {
                fmt.Printf("'%s' is not exist\n", file)
                return false
        }

        return true
}

func zoneCityIsValid(tz string) bool {
        return isElementExist(tz, zoneCityInfo)
}

func isElementExist(element string, list []string) bool {
        for _, v := range list {
                if v == element {
                        return true
                }
        }

        fmt.Printf("'%s' is not exist in list\n", element)
        return false
}
